#pragma once
#include <cstdint>
#include <cstring>
#include <map>
#include <memory>
#include <mutex>

namespace xncc {
class AsyncLogQueueElement;

class AsyncLogQueue
{
  public:
    using s_ptr = std::shared_ptr<AsyncLogQueue>;
    explicit AsyncLogQueue(uint64_t size);
    ~AsyncLogQueue() = default;

    AsyncLogQueue(AsyncLogQueue&&)                         = delete;
    AsyncLogQueue(const AsyncLogQueue&)                    = delete;
    auto operator=(AsyncLogQueue&&) -> AsyncLogQueue&      = delete;
    auto operator=(const AsyncLogQueue&) -> AsyncLogQueue& = delete;

    auto getWriteBuffer(uint64_t len) -> char*;
    auto tryGetWriteBuffer(uint64_t len) -> char*;
    void finishWrite();
    auto getReadBuffer(uint64_t len) -> char*;
    void finishRead();

    auto canDestory() const -> bool
    {
        return canDestory_;
    }

    void setCanDestory()
    {
        canDestory_ = true;
    }

    bool empty() const;

  private:
    void updateCurrentReadPtr();
    void updateCurrentWritePtr();

    std::map<int, std::shared_ptr<AsyncLogQueueElement>> bufferList_;
    std::shared_ptr<AsyncLogQueueElement>                currReadPtr_;
    std::shared_ptr<AsyncLogQueueElement>                currWritePtr_;
    std::mutex                                           mutex_;
    int                                                  lastReadIndex_;
    const int                                            queueId_;
    bool                                                 canDestory_;
    static constexpr uint64_t                            MAX_SINGLE_QUEUE_LENGTH = 2048L * 1024 * 1024;  // 2G
};
}  // namespace xncc
